import beautify from 'js-beautify'
import makeForm from './form'

const apiConfig = (apiJson) => {
  let tags = []
  if (apiConfig.tags) {
    tags = apiJson.tags || []
  } else {
    let p = apiJson.paths
    if (p) {
      let pathKeys = Object.keys(p)
      pathKeys.forEach((k) => {
        let pathItem = p[k]
        let itemKeys = Object.keys(pathItem)
        let method = itemKeys[0]
        let item = pathItem[method]
        let tag = item.tags ? item.tags[0] : null
        let t = tags.find(e => e.name === tag)
        if (!t && tag != null) {
          tags.push({
            name: tag,
            description: item.description,
          })
        }
      })
    }
  }
  const paths = apiJson.paths || {}
  return {
    tags,
    paths,
    definitions: apiJson.definitions || {},
  }
}

const apiMapInit = (tags) => {
  const m = {}
  tags.map((tag) => {
    if (tag.name !== '') {
      m[tag.name] = []
    }
  })
  return m
}

const apiMap = (apiPrefix = '', paths, apiMap) => {
  const m = JSON.parse(JSON.stringify(apiMap))
  const dict = {
    新增: {
      prefix: 'add',
      label: '新增',
    },

    添加: {
      prefix: 'add',
      label: '添加',
    },

    修改: {
      prefix: 'update',
      label: '修改',
    },

    删除: {
      prefix: 'del',
      label: '删除',
    },

    详情: {
      prefix: 'detail',
      label: '详情',
    },
    列表: {
      prefix: 'list',
      label: '列表',
    },
    分页: {
      prefix: 'pagination',
      label: '分页',
    },
    记录: {
      prefix: 'record',
      label: '记录',
    },
    查询: {
      prefix: 'search',
      label: '分页',
    },
    测试: {
      prefix: 'test',
      label: '测试',
    },
    get: {
      prefix: 'get',
      label: '新增',
    },
    post: {
      prefix: 'update',
      label: '修改',
    },
    put: {
      prefix: 'put',
      label: '修改',
    },
    delete: {
      prefix: 'del',
      label: '删除',
    },
  }
  // const dictKeys = Object.keys(dict);
  const keyword = [
    'export',
    'break',
    'else',
    'new',
    'var',
    'case',
    'finally',
    'return',
    'void',
    'catch',
    'for',
    'switch',
    'while',
    'continue',
    'function',
    'this',
    'with',
    'default',
    'if',
    'throw',
    'delete',
    'in',
    'try',
    'do',
    'instranceof',
    'typeof',
  ]
  // 分类所有api
  Object.keys(paths).forEach((path) => {
    const item = paths[path]
    let keyList = ['get', 'post', 'put', 'delete'].concat(Object.keys(item))
    let methodKey = keyList.filter((item, index, self) => {
      return self.indexOf(item) !== index
    })
    if (methodKey.length > 0) {
      const method = (methodKey[0] || '').toLocaleLowerCase()
      const tagName = item[method].tags[0] || '' // 所属文件夹
      const summary = item[method].summary
        ? `${tagName} : ${item[method].summary}`
        : tagName // 接口简单描述
      const params = item[method].parameters || []
      let pathList = path.split('/')
      let lastPath
      if (!pathList[pathList.length - 1].includes('{')) {
        // 如果 path 不使用 路径参数, 使用路径最后的名字命名 api 函数名称
        lastPath = pathList[pathList.length - 1]
          ? pathList[pathList.length - 1].replace(new RegExp('-', 'g'), '')
          : ''
      } else {
        lastPath = pathList[pathList.length - 2]
          ? pathList[pathList.length - 2].replace(new RegExp('-', 'g'), '')
          : ''
      }
      // let key = dictKeys.find((key) => {
      //   let s = item[method].summary;
      //   if (s) {
      //     return s.includes(key);
      //   } else {
      //     return null;
      //   }
      // });
      let methodType = dict[method]
      let tagList = m[tagName]
      let apiName = lastPath.replace(lastPath[0], lastPath[0])
      tagList.push({
        summary,
        path: apiPrefix + path,
        params,
        method,
        apiName:
          keyword.includes(apiName)
            ? methodType.prefix
              + lastPath.replace(lastPath[0], lastPath[0].toUpperCase())
            : lastPath.replace(lastPath[0], lastPath[0]),
        // apiName:
        //   methodType.prefix +
        //   lastPath.replace(lastPath[0], lastPath[0].toUpperCase()),
      })
    }
  })
  return m
}

const apiDescriptions = (config) => {
  // 添加 参数 描述
  let paramsDoc = ''
  config.params.forEach((p) => {
    let type
    if (p.type) {
      type = p.type
    } else {
      if (p.schema) {
        if (p.schema.originalRef) {
          type = 'object'
        } else {
          if (p.schema.type) {
            type = p.schema.type
          } else {
            type = ''
          }
        }
      } else {
        type = ''
      }
    }
    paramsDoc
      += '\r\n'
      + `* @param { ${type} } ${p.name} - ${
        p.description
      } ( required: ${p.required || false} )`
  })
  return { desc: `${config.summary}${paramsDoc}` }
}

const apiTemplate = ({ requestName = 'request', config }) => {
  // params in path, query, body
  let { params, dataConfig, pathParams } = apiParams(config)
  let { desc } = apiDescriptions(config)
  const requestConfig = {
    method: `'${config.method}'`,
    path: `${config.path}`,
  }
  let tPath = '`' + `${requestConfig.path}` + '`'
  if (pathParams.length > 0) {
    // 替换路径上的参数为模板语法
    tPath = tPath.replace(/{/g, '${')
  }
  let lengthFlag = params.split(',').length > 3 // 参数大于3个
  let t = `/*
${desc}
*/
export const ${config.apiName} = (${lengthFlag ? 'params' : params}) => {
    return ${requestName}({
        method: ${requestConfig.method},
        url: ${pathParams.length > 0 ? tPath : `'${requestConfig.path}'`},${
    dataConfig.params ? `params: { ${lengthFlag ? '...params' : dataConfig.params}},` : ''
  }${dataConfig.data ? `data: { ${lengthFlag ? '...params' : dataConfig.data} },` : ''}
    })
}

`
  return t
}

const apiParams = (config) => {
  const { path, query, body } = apiConfigParams(config)
  let dataConfig = {}
  let params = ''
  if (path.length > 0) {
    params += path.join(', ')
  }

  if (query.length > 0) {
    let q = query.join(', ')
    dataConfig.params = `${q}`
    params += q
  }
  if (body.length > 0) {
    let d = body.join(', ')
    dataConfig.data = `${d}`
    params += d
  }

  return { params, dataConfig, pathParams: path }
}

const apiConfigParams = (config) => {
  let list = config.params
  let query = []
  let body = []
  let path = []

  list.forEach((p) => {
    let paramName = p.name
    let i = p.in
    if (i === 'path') {
      path.push(paramName)
    } else if (i === 'query') {
      query.push(paramName)
    } else if (i === 'body') {
      body.push(paramName)
    }
  })
  return { path, query, body }
}

const apiFile = (requestName, apiconfig) => {
  let apiList = []
  let keys = Object.keys(apiconfig)
  keys.forEach((k) => {
    let list = apiconfig[k]
    if (list) {
      apiList.push([
        [k],
        [...list.map(config => apiTemplate({ requestName, config }))],
      ])
    }
  })

  return apiList
}

const objectProperties = (definitions, label = false) => {
  let type = ['string', 'boolean', 'integer', 'number', 'object']
  let value = ['\'\'', false, null, null, '{}']
  let keys = Object.keys(definitions)
  let data = ''
  let dataLabel = ''
  keys.forEach((k) => {
    let item = definitions[k]
    let oKey = k
    // 判断 id 只获取实体类
    if (item.properties && Object.prototype.hasOwnProperty.call(item.properties, 'id')) {
      if (item.type === 'object') {
        let properties = item.properties
        let propKeys = Object.keys(properties)
        let o = ''
        let m = ''
        propKeys.forEach((pkey) => {
          let pItem = properties[pkey]
          let index = type.findIndex(e => e === pItem.type)
          if (index !== -1) {
            o += `'${pkey}': ${value[index]}, // ${pItem.description}\r\n`
          } else {
            o += `'${pkey}': null,\r\n`
          }
          m += `'${pkey}': { prop: '${pkey}', label: '${pItem.description}' }, // ${pItem.description}\r\n`
        })
        let obj = `{${o}}`
        data += `'${oKey.slice(0).toLocaleLowerCase() + oKey.slice(1)}': ${obj},
                `
        if (label === true) {
          let objLabel = `{${m}}`
          dataLabel += `'${oKey.slice(0).toLocaleLowerCase()
            + oKey.slice(1)}': ${objLabel},
                  `
        }
      }
    }
  })
  let item = {
    modelData: `{${data}}`,
  }
  if (label === true) {
    item.dataLabel = `{${dataLabel}}`
  }
  return item
}

const service = async ({
  requestName = 'request',
  apiPath,
  json = null,
  apiPrefix = '',
  importPath,
  modelLabel = false,
}) => {
  // const apiJson = require(apiPath);
  let apiJson = {}
  if (json) {
    apiJson = json
  } else {
    apiJson = await fetch(apiPath).then(res => res.json())
  }
  const { tags, paths, definitions } = apiConfig(apiJson)
  let m = apiMapInit(tags)
  let data = apiMap(apiPrefix, paths, m)
  let list = apiFile(requestName, data)
  let { modelData, dataLabel } = objectProperties(definitions, modelLabel)
  // const fs = require("fs");
  const beautifyFn = beautify.js
  try {
    let option = {
      indent_size: 4,
      space_in_empty_paren: true,
    }
    let allData = {
      api: {},
    }
    list.forEach((file) => {
      let fileName = file[0]
      let requestPath = importPath ? `${importPath}\r\n\r\n` : ''
      let fileContent = requestPath + file[1].join('')
      let formatContent = beautifyFn(fileContent, option)
      // fs.writeFileSync(`../${fileName}.js`, formatContent, {
      //   encoding: "utf8",
      // });
      allData.api[fileName] = formatContent
    })
    const formatModelData = beautifyFn(modelData, option)
    // fs.writeFileSync("../model.js", formatModelData, {
    //   encoding: "utf8",
    // });
    allData.model = formatModelData
    if (modelLabel === true) {
      const formatModelLabelData = beautifyFn(dataLabel, option)
      // fs.writeFileSync("../modelable.js", formatModelLabelData, {
      //   encoding: "utf8",
      // });
      allData.modelLabel = formatModelLabelData
    }
    return allData
  } catch (err) {
    console.error(err)
  }
}
export { service, makeForm }
